home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 427_01 / software / multijoy.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1994-03-23  |  11.7 KB  |  385 lines

  1. unit multijoy; (* reads out status of the MULTI JOYSTICK INTERFACE *)
  2.  
  3.  
  4. (* MULTIJOY uses four DOS environment variables:
  5.  
  6.    MULTIPATH  is the path where the config file is located
  7.    MULTICFG   is the name of the config file without extension
  8.    MULTIPORT  is optional and states the printer port to be used
  9.               (port 1 is the default if MULTIPORT is empty)
  10.    MULTIDELAY is optional, too. It's the number of NOPs executed to wait
  11.               for the joystick interface between writing and reading the
  12.               printer port status (MULTIDELAY is only necessary if you have
  13.                 a) a VERY fast computer or
  14.                 b) a VERY slow interface (i.e. a CMOS type) *)
  15.  
  16.  
  17. interface
  18.  
  19.  
  20. const maxplayer = 6;             (* maximum number of players *)
  21.  
  22. type TJoy = record
  23.               x, y         : shortint; (* -1 .. +1 (minus is left/up) *)
  24.               lhit,  rhit,             (* directions triggered?       *)
  25.               uhit,  dhit,             (* directions triggered?       *)
  26.               khit,  xhit,             (* buttons triggered?          *)
  27.               knopf, xtra  : boolean;  (* buttons held down?          *)
  28.             end;
  29.  
  30.      TJoyState  = array [1 .. maxplayer] of TJoy;
  31.  
  32.      TJoyNum    = array [1 .. maxplayer] of byte;
  33.  
  34. var  JoyState   : TJoyState;
  35.      (* contains all joystick status information *)
  36.      (* is updated by calling GetAllJoyState     *)
  37.  
  38.      RealJoyNum,
  39.      JoyNum     : TJoyNum;
  40.      (* JoyNum [Player] contains physical joystick number of logical player *)
  41.  
  42.      MultiJoyInstalled : boolean;
  43.      (* read-only, TRUE if MULTIJOY is active, FALSE otherwise      *)
  44.      (* if installation is unsuccessful, MULTIJOY usually HALTs     *)
  45.      (* exception: no DOS environment variables stated at all       *)
  46.      (* If your program depends on MULTIJOY, it should HALT with an *)
  47.      (* appropriate error message if MULTIJOYINSTALLED is FALSE.    *)
  48.  
  49.  
  50. procedure InitMultiJoy;
  51. (* MULTIJOY initializes itself, but you can initialize again if you want *)
  52.  
  53. procedure GetAllJoyState;
  54. (* gets status of all joystick ports *)
  55.  
  56. function  ChangeJoyNum : boolean;
  57. (* changes joystick assignment defined by JoyNum                           *)
  58. (* TRUE if no joystick is used more than once and 1 <= JoyNum <= MAXPLAYER *)
  59.  
  60. procedure ResetJoyNum;
  61. (* resets joystick assignment and JoyNum array to initial status *)
  62.  
  63. procedure EmulationOn;
  64. (* enables emulation (if config file contains keyword 'KEYBOARD') *)
  65.  
  66. procedure EmulationOff;
  67. (* disables emulation (if enabled) *)
  68.  
  69.  
  70. implementation
  71.  
  72.  
  73. uses crt, dos, multierr, multikbd;
  74.  
  75. type TDecode  = record
  76.                   stikno1 : byte;
  77.                   action1 : char;
  78.                   stikno2 : byte;
  79.                   action2 : char;
  80.                 end;
  81.  
  82. const zero_action : TJoy
  83.                   = (x     : 0    ; y    : 0;
  84.                      lhit  : false; rhit : false;
  85.                      uhit  : false; dhit : false;
  86.                      khit  : false; xhit : false;
  87.                      knopf : false; xtra : false);
  88.       actionchars = (['L', 'R', 'U', 'D', 'F', '*']);
  89.  
  90. var multipath    : string;
  91.     multicfg     : string [8];
  92.     multiport    : string [1];
  93.     multidelay   : string [5];
  94.     delaycount   : word;
  95.     printer_port : byte;
  96.     pout,
  97.     p_in         : word;
  98.     decode       : array [0 .. 15] of TDecode;
  99.     key_number   : array [1 .. 2, 0 .. 4] of byte;
  100.     PlayerNum    : TJoyNum;                    (* Inversion of JoyNum *)
  101.     keyboard,
  102.     invert,
  103.     disabled     : boolean;
  104.  
  105.  
  106. function read_port (mjoyaddress : byte) : byte;
  107. (* sets MULTI JOYSTICK INTERFACE to address MJOYADDRESS *)
  108. (* reads printer port, i.e. PAPER EMPTY and BUSY bits   *)
  109. begin
  110.   port [pout] := mjoyaddress;
  111.   asm
  112.     mov  cx, delaycount
  113.   @l:
  114.     nop
  115.     loop @l
  116.   end;
  117.   if invert then read_port := not port [p_in]
  118.             else read_port :=     port [p_in];
  119. end;
  120.  
  121.  
  122. procedure error_msg (msg_nr, code : integer);
  123. (* calls MULTIERR error message procedure *)
  124. begin
  125.   multierr.error_msg (msg_nr, code, multipath, multicfg, multiport);
  126. end;
  127.  
  128.  
  129. function ChangeJoyNum : boolean;
  130. (* changes joystick assignment defined by JoyNum                           *)
  131. (* TRUE if no joystick is used more than once and 1 <= JoyNum <= MAXPLAYER *)
  132. var i    : integer;
  133.     used : array [1 .. maxplayer] of boolean;
  134.     good : boolean;
  135. begin
  136.   for i := 1 to maxplayer do begin
  137.     joynum [i] := realjoynum [joynum [i]];
  138.     used   [i] := false;
  139.   end;
  140.   realjoynum := joynum;
  141.  
  142.   changejoynum := true;
  143.   for i := 1 to maxplayer do
  144.     if not used [i] and (joynum [i] >= 1) and (joynum [i] <= maxplayer)
  145.       then PlayerNum [JoyNum [i]] := i
  146.       else changejoynum := false;
  147. end;
  148.  
  149.  
  150. procedure ResetJoyNum;
  151. (* resets joystick assignment and JoyNum array to initial status *)
  152. var i : integer;
  153. begin
  154.   for i := 1 to maxplayer do joynum [i] := i;
  155.   realjoynum := joynum;
  156.   changejoynum;
  157. end;
  158.  
  159.  
  160. procedure InitMultiJoy;
  161. (* reads interface pin assignment from disk *)
  162. (* resets joystick status variables         *)
  163. var cmdline   : string [8];
  164.     cfg       : text;
  165.     i,
  166.     j,
  167.     k,
  168.     error     : integer;
  169.     dummy     : char;
  170.  
  171.  
  172.   function get_port_no (port_no : char) : byte;
  173.   (* find printer port number in a string *)
  174.   begin
  175.     if not (port_no in ['1' .. '3']) then error_msg (8, ord (port_no));
  176.     get_port_no := ord(port_no)-ord('0');
  177.   end;
  178.  
  179.  
  180. begin
  181.   multipath := getenv ('multipath'); (* read environment variables *)
  182.   multicfg  := getenv ('multicfg' );
  183.   multiport := getenv ('multiport');
  184.   multidelay:= getenv ('multidelay');
  185.   if multidelay<>'' then begin
  186.     val(multidelay,delaycount,error);
  187.     if error<>0 then error_msg (13,0);
  188.     inc(delaycount);
  189.   end else
  190.     delaycount:=1;
  191.  
  192.   if (multipath + multicfg + multiport) = '' then disabled := true
  193.                                              else disabled := false;
  194.  
  195.   if not disabled then begin
  196.     if multiport = ''  then printer_port := 1 (* default!   *)
  197.                        else printer_port := get_port_no (multiport [1]);
  198.  
  199.     pout := memw [$40:$8 + (printer_port-1) * 2];
  200.     if pout = 0 then error_msg (11, printer_port);
  201.     p_in := pout + 1;
  202.  
  203.     if multipath           = ''  then error_msg (5, 0); (* undefined? *)
  204.     if multicfg            = ''  then error_msg (6, 0); (* undefined? *)
  205.     if pos ('.', multicfg) >  0  then error_msg (7, 0); (* extension? *)
  206.  
  207.     if multipath[length(multipath)]='\' then
  208.       assign (cfg, multipath + multicfg + '.cfg')
  209.     else
  210.       assign (cfg, multipath + '\' + multicfg + '.cfg');
  211.  
  212.     {$I-}
  213.     reset(cfg);
  214.     {$I+}
  215.     error := ioresult;
  216.     if error <> 0 then error_msg (1, error);
  217.  
  218.     readln (cfg, cmdline);
  219.     if (cmdline = 'keyboard') or (cmdline = 'KEYBOARD') then keyboard := true
  220.                                                         else keyboard := false;
  221.  
  222.     if not keyboard then begin
  223.       reset (cfg);
  224.       for i := 0 to 15 do begin
  225.         with decode [i] do begin
  226.           if eof (cfg) then error_msg (3, 0);
  227.           {$I-}
  228.           readln (cfg, j, stikno1, dummy, action1, stikno2, dummy, action2);
  229.           {$I+}
  230.           error := ioresult;
  231.           if error <> 0 then error_msg (4, error);
  232.           if (stikno1 < 1) or (stikno1 > maxplayer) then error_msg (12, stikno1);
  233.           action1 := upcase (action1);
  234.           if not (action1 in actionchars) then error_msg (2, ord (action1));
  235.           if (stikno2 < 1) or (stikno2 > maxplayer) then error_msg (12, stikno2);
  236.           action2 := upcase (action2);
  237.           if not (action2 in actionchars) then error_msg (2, ord (action2));
  238.         end;
  239.       end;
  240.       if not eof (cfg) then readln (cfg, cmdline)
  241.                        else cmdline := '';
  242.       if (cmdline = 'invert') or (cmdline = 'INVERT') then invert := true
  243.                                                       else invert := false;
  244.       close (cfg);
  245.     end else begin
  246.       for i := 1 to 2 do
  247.         for j := 0 to 4 do begin
  248.           if eof (cfg) then error_msg (3, 0);
  249.           {$I-}
  250.           readln (cfg, dummy, dummy, k);
  251.           {$I+}
  252.           error := ioresult;
  253.           if error <> 0 then error_msg (4, error);
  254.           key_number [i, j] := k;
  255.         end;
  256.       init_kbd;
  257.     end;
  258.     multijoyinstalled := true;
  259.   end else
  260.     multijoyinstalled := false;
  261.  
  262.   (* initialize joystick status variables *)
  263.   for i:=1 to maxplayer do begin
  264.     RealJoyNum [i] := i;
  265.     JoyNum     [i] := i;
  266.     JoyState   [i] := zero_action;
  267.   end;
  268.   ChangeJoyNum;
  269. end;
  270.  
  271.  
  272. procedure EmulationOn;
  273. (* enables emulation (if config file contains keyword 'KEYBOARD') *)
  274. begin
  275.   if keyboard then init_kbd;
  276. end;
  277.  
  278.  
  279. procedure EmulationOff;
  280. (* disables emulation (if enabled) *)
  281. begin
  282.   if keyboard then reset_kbd;
  283. end;
  284.  
  285.  
  286. procedure GetAllJoyState;
  287. (* gets status of all joysticks *)
  288. var address,
  289.     joy,
  290.     plr_now,
  291.     player,
  292.     pebu     : byte; (* PAPER EMPTY and BUSY bits *)
  293.     old      : array [1 .. maxplayer] of record
  294.                                            ox,
  295.                                            oy : shortint;
  296.                                            ok,
  297.                                            oe : boolean;
  298.                                           end;
  299.  
  300.  
  301.   procedure GetKeyState (joy : integer);
  302.   (* gets status of joystick emulating keys *)
  303.   begin
  304.     with joystate [playernum [joy]] do
  305.       with old [playernum [joy]] do begin
  306.         if key [key_number [joy, 0]]
  307.           then begin
  308.             x    := - 1;
  309.             lhit := - 1 <> ox;
  310.           end else
  311.             if key [key_number [joy, 1]] then begin
  312.               x    := 1;
  313.               rhit := 1 <> ox;
  314.             end;
  315.         if key [key_number [joy, 2]] then begin
  316.             y    := - 1;
  317.             uhit := - 1 <> oy;
  318.           end else
  319.             if key [key_number [joy, 3]] then begin
  320.               y    := 1;
  321.               dhit := 1 <> oy;
  322.             end;
  323.         if key [key_number [joy, 4]] then begin
  324.           knopf := true;
  325.           khit  := not ok;
  326.         end;
  327.       end;
  328.   end;
  329.  
  330.  
  331.   procedure decode_joystate (decode_action : char);
  332.   (* decodes joystick status *)
  333.   (* note: if you manage to invoke two opposite directions at the same *)
  334.   (* time, the hit-indicators will be misleading                       *)
  335.   begin
  336.     with joystate [plr_now] do
  337.       with old [plr_now] do begin
  338.         case decode_action of
  339.           'L' : begin x := - 1; lhit := - 1 <> ox;   end;
  340.           'R' : begin x :=   1; rhit :=   1 <> ox;   end;
  341.           'U' : begin y := - 1; uhit := - 1 <> oy;   end;
  342.           'D' : begin y :=   1; dhit :=   1 <> oy;   end;
  343.           'F' : begin knopf := true; khit := not ok; end;
  344.           '*' : begin xtra  := true; xhit := not oe; end;
  345.         end;
  346.     end;
  347.   end;
  348.  
  349.  
  350. (* GetAllJoyState *)
  351. var i : integer;
  352. begin
  353.   for joy := 1 to maxplayer do begin
  354.     with JoyState [playernum [joy]] do
  355.       with old [playernum [joy]] do begin
  356.         ox := x;
  357.         oy := y;
  358.         ok := knopf;
  359.         oe := xtra;
  360.       end;
  361.     JoyState [playernum [joy]] := zero_action;
  362.   end;
  363.  
  364.   if not disabled then begin
  365.     if not keyboard then
  366.       for address := 0 to 15 do begin
  367.         pebu := read_port (address);
  368.         (* first bit *)
  369.         plr_now := playernum [decode [address].stikno1];
  370.         if (pebu and $20) <> 0 then decode_joystate (decode [address].action1);
  371.         (* second bit *)
  372.         plr_now := playernum [decode [address].stikno2];
  373.         if (pebu and $80) =  0 then decode_joystate (decode [address].action2);
  374.       end else begin
  375.         GetKeyState (1);
  376.         GetKeyState (2);
  377.       end;
  378.   end;
  379. end;
  380.  
  381.  
  382. (* MultiJoy *)
  383. begin
  384.   InitMultiJoy;
  385. end.